package com.love.cloud.admin.notify.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.love.cloud.admin.api.vo.UserVO;
import com.love.cloud.admin.mapper.SysUserMapper;
import com.love.cloud.admin.notify.entity.NotifyArticle;
import com.love.cloud.admin.notify.entity.NotifyPicture;
import com.love.cloud.admin.notify.mapper.NotifyArticleMapper;
import com.love.cloud.admin.notify.mapper.NotifyPictureMapper;
import com.love.cloud.admin.notify.service.NotifyArticleService;
import com.love.cloud.admin.notify.vo.ArticleVo;
import com.love.cloud.common.core.config.SseEmitterServer;
import com.love.cloud.common.core.exception.BusinessException;
import com.love.cloud.common.core.util.RedisUtils;
import com.love.cloud.common.mybatis.util.PageUtils;
import com.love.cloud.common.security.service.SosUser;
import com.love.cloud.common.security.util.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * @author hongdongqu
 */
@Service
public class NotifyArticleServiceImpl extends ServiceImpl<NotifyArticleMapper, NotifyArticle> implements NotifyArticleService {
    @Resource
    private PageUtils pageUtils;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private NotifyPictureMapper notifyPictureMapper;

    private final static String article_views="article_views:";
    private final static String article_praise="article_praise:";

    @Override
    public Object allArticlePage(ArticleVo articleVo) {
        return baseArticlePage(articleVo,true);
    }

    @Override
    public Object articlePage(ArticleVo articleVo) {
        return baseArticlePage(articleVo,true);
    }

    private Object baseArticlePage(ArticleVo articleVo,Boolean isSearchUser){
        Page<NotifyArticle> page = pageUtils.page();
        NotifyArticle article = new NotifyArticle();
        BeanUtils.copyProperties(articleVo,article);
        article.setDelFlag(0);
        if(isSearchUser){
            SosUser sosUser = SecurityUtils.getUser();
            article.setUserId(sosUser.getId());
        }
        this.baseMapper.articlePage(page,article);
        for (NotifyArticle notifyArticle:page.getRecords()) {
            //获取缓存中的观看数量
            notifyArticle.setLookNum(this.getPostViewsByPostId(notifyArticle.getId(),notifyArticle.getLookNum()));
            //获取缓存中的点赞数量
            notifyArticle.setPraiseNum(this.getPraiseNum(notifyArticle.getId()));
        }
        return page;
    }

    /**
     * 查看文章内容
     * @param articleId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public NotifyArticle viewArticle(Long articleId){
        NotifyArticle article= this.getById(articleId);
        if(article!=null&&article.getUserId()!=null){
            //获取用户信息
            UserVO userVO = sysUserMapper.getUserVoById(article.getUserId());
            article.setUserVO(userVO);
        }
        SosUser sosUser = SecurityUtils.getUser();
        if(article.getUserId()==sosUser.getId()){
            //不更新观看数量，只赋值
            article.setLookNum(this.getPostViewsByPostId(article.getId(),article.getLookNum()));
        }else{
            //更新观看数量，并赋值
            article.setLookNum(this.updatePostView(article.getId(),article.getLookNum()));
        }
        //获取缓存中的点赞数量
        article.setPraiseNum(this.getPraiseNum(article.getId()));
        //判断用户是否点赞了
        if(sosUser.getId()!=null){
            article.setIsPraise(this.isPraiseByUser(article.getId(),sosUser.getId()));
        }else{
            article.setIsPraise(false);
        }
        return article;
    }

    /**
     * 保存文章内容
     * @param notifyArticle
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int saveArticle(NotifyArticle notifyArticle){
        if(notifyArticle.getId()==null){
            SosUser sosUser = SecurityUtils.getUser();
            notifyArticle.setUserId(sosUser.getId());
            notifyArticle.setCommentNum(0);
            notifyArticle.setPraiseNum(0);
            notifyArticle.setLookNum(0);
            this.save(notifyArticle);
            for (NotifyPicture picture :notifyArticle.getPictureList()) {
                picture.setArticleId(notifyArticle.getId());
                notifyPictureMapper.insert(picture);
            }
        }else{
            notifyArticle.setUpdateTime(LocalDateTime.now());
            this.updateById(notifyArticle);
            //直接物理删除全部图片
            QueryWrapper<NotifyPicture> queryWrapper=new QueryWrapper<>();
            queryWrapper.lambda().eq(NotifyPicture::getArticleId,notifyArticle.getId());
            notifyPictureMapper.deletePhysicsById(queryWrapper); //配置了逻辑删除，所以只执行逻辑删除
            //添加新的图片
            for (NotifyPicture picture :notifyArticle.getPictureList()) {
                picture.setArticleId(notifyArticle.getId());
                notifyPictureMapper.insert(picture);
            }
        }
        return 1;
    }

    @Override
    public int pushArticle(NotifyArticle notifyArticle) {
        //保存文章状态
        this.updateById(notifyArticle);
        NotifyArticle one = this.getById(notifyArticle.getId());
        //发送see消息
        Map<String,String> noticeMap=new HashMap<>();
        noticeMap.put("notice","《"+one.getTitle()+"》发布.请注意查看");
        SseEmitterServer.batchSendMessage(JSON.toJSONString(noticeMap));
        return 1;
    }

    /**
     * 用户点赞
     *
     */
    @Override
    public Long praiseArticle(Long articleId,Long userId) {
        Long num =redisUtils.sSet(article_praise + articleId,userId);
        if(num==0){
            throw new BusinessException(500,"未点赞成功");
        }
        return num;
    }

    /**
     * 用户取消点赞
     */
    @Override
    public Long cancelPraiseArticle(Long articleId,Long userId) {
        Long num =redisUtils.setRemove(article_praise + articleId,userId);
        if(num==0){
            throw new BusinessException(500,"取消点赞失败");
        }
        return num;
    }

    /**
     * 修改文章阅读量
     * Redis增加，定时器同步，外部传入mysql中的值
     *
     * @param avatarId 文章Id
     */
    private Integer updatePostView(Long avatarId,Integer lookNum) {
        Integer view = this.getPostViewsByPostId(avatarId,lookNum);
        if (view == null) {
            return null;
        }
        return redisUtils.incr(article_views + avatarId, 1).intValue();
    }

    /**
     * 获得某篇文章的访问量，外部传入mysql中的值
     *
     * @return Long
     */
    private Integer getPostViewsByPostId(Long avatarId,Integer lookNum) {
        Object str =redisUtils.get(article_views + avatarId);
        if (str == null) {
            redisUtils.set(article_views + avatarId, String.valueOf(lookNum));
            return lookNum;
        }
        return Integer.parseInt(String.valueOf(str));
    }

    /**
     * 获取点赞数量
     */
    public Integer getPraiseNum(Long avatarId){
        Long num=redisUtils.sGetSetSize(article_praise + avatarId);
        return num.intValue();
    }

    /**
     * 判断当前用户是否点赞了
     */
    private Boolean isPraiseByUser(Long avatarId,Long userId){
        Boolean t =redisUtils.sHasKey(article_praise + avatarId,userId);
        return t;
    }

}
